const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {

  status = PENDING
  successfulCallback = []
  failCallback = []
  value = void 0
  reason = void 0
  constructor(fn) {
    //构建函数中传入函数，并立即执行
    try {
      //处理执行器内部异常
      fn(this.resolve, this.reject)
    } catch(e) {
      this.reject(e)
    }
    
  }

  resolve = (value) => {
    //确保promise状态确定后不可更改
    if (this.status !== PENDING) return 
    this.status = FULFILLED
    this.value = value
    while(this.successfulCallback.length) this.successfulCallback.shift()()
  }
  reject = (reason) => {
    //确保promise状态确定后不可更改
    if (this.status !== PENDING) return
    this.status = REJECTED
    this.reason = reason
    while(this.failCallback.length) this.failCallback.shift()()
  }

  then(successfulCb, failCb) {
    //promise对象的then方法的参数可选，如果当前promise的then方法里缺省回调函数的话，就将当前结果透传到下个then中
    successfulCb = successfulCb ? successfulCb : value => value
    failCb = failCb ? failCb : reason => { throw reason }
    let newPromise = new Promise((resolve, reject) => {
      let fulfilledProcess = () => {
        setTimeout(() => {
          //捕获成功回调函数执行内部的错误
          try {
            let result = successfulCb(this.value)
            resolvePromise(newPromise, result, resolve, reject)
          } catch (e) {
            reject(e)
          }

        }, 0);
      }
      let rejectedProcess = () => {
        setTimeout(() => {
          //捕获失败回调函数执行内部的错误
          try {
            let result = failCb(this.reason)
            resolvePromise(newPromise, result, resolve, reject)
          } catch (e) {
            reject(e)
          }

        }, 0);
      }
      if (this.status === FULFILLED) {
        //因为要判断promise内部不能返回自身，所以需要把then中新创建的newPromise和这个promise的结果作比较，
        //因此，需要一部调用settimeout方法，去添加一个异步任务，以便在resolvePromise方法中拿到newPromise
        fulfilledProcess()
      } else if (this.status === REJECTED) {
        //同上
        rejectedProcess()
      } else {
        this.successfulCallback.push(() => {
          fulfilledProcess()
        })
        this.failCallback.push(() => {
          rejectedProcess()
        })
      }
    })
    return newPromise
  }
  
  static all(array) { 
    //方法分析
    //1、all方法的参数是一个数组，这个数组中的各项可以是普通值也可以是promise
    //2、all方法后链式调用的then方法，所以首先all方法要返回一个新的promise，然后再他的then回调中接收一个数组，是参数里各项的返回值
    //3、在执行这个新promise的执行器的时候需要遍历传入的参数数组
    //4、逐一去判断这个数组的每一项是否是普通值或者是promise对象，
    //5、如果是普通值则把这个值resolve，如果是promise，需要用promise的then方法将promise成功的执行结果添加到结果数组中，并将计数器加1
    //   将执行失败的结果reject，则当前promiseall方法是失败的
    //6、判断计数器的值是否和参数数组长度相等，相等则说明当前数组的所有返回值都拿到了，这时就将整个结果数组resolve
    let resultArray = []
    let count = 0
    return new MyPromise((resolve, reject) => {
      function addItem (value, index) {
        resultArray[index] = value
        count++
        if (count === array.length) resolve(resultArray)
      }
      array.forEach((item, index) => {
        if (item instanceof MyPromise) {
          item.then((value) => {
            addItem(value, index)
          }, (reason) => {reject(reason)})
        } else {
          addItem(item, index)
        }
        
      })
    })
  }

  static resolve(value) {
    //方法分析
    //1、功能分析：Promise.resolve功能是将给定的值转换成promise对象
    //2、resolve方法接收1个参数，这个参数可以是普通值也可以是promise对象
    //3、如果是promise对象，则原样返回，否则重新包装一个promise并把value用resolve返回
    if (value instanceof MyPromise) {
      return value
    } else {
      return new MyPromise((resolve, reject) => {
        resolve(value)
      })
    }
  }
  finally(callback) {
    //方法分析
    //1、无论promise方法成功或失败，都会执行一次finally
    //2、在finally方法后面可以链式调用then方法，所以finally方法返回一个新的promise
    //3、在当前promise的两种不同状态下分别将callback的调用值包装成promise并返回
    return this.then(() => {
      return MyPromise.resolve(callback()).then((value) => value)
    }, () => {
      return MyPromise.resolve(callback()).then((reason) => { throw reason })
    })
  }
  catch(failCb) {
    //catch方法仅接收一个失败回调
    return this.then(void 0, failCb)
  }
  static race(array) {
    return new MyPromise((resolve, reject) => {
      for(let i = 0; i < array.length; i++) {
        if (array[i] instanceof MyPromise) {
          array[i].then((value) => {
            resolve(value)
            i=array.length
          }, (reason) => {
            reject(reason)
          })
        } else {
          resolve[array[i]]
          i = array.length
        }
      }
    })
  }
}


function resolvePromise(newPromise, result, resolve, reject) {
  //检查当前then返回的promise对象不能是它本身
  if (newPromise === result) return reject(new TypeError('[TypeError: Chaining cycle detected for promise #<Promise>]'))
  if (result instanceof MyPromise) {
    result.then(resolve, reject)
  } else {
    resolve(result)
  }
}

// let p1 = new MyPromise((resolve, reject) => {
//   setTimeout(() => {
//       reject(1)

//   }, 100);
// })
// let p2 = new MyPromise((resolve, reject) => {
//   setTimeout(() => {
//       resolve(2)

//   }, 200);
// })

// p1.then((value) => {
//   console.log(value)
  
// },(reason) => {
//   console.log('reason:', reason)
//   return p2
// }).then((value) => {
//   console.log(value)
// })


